#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
MCP 数学运算服务器

这是一个基于MCP协议的数学运算服务器，提供基础数学运算功能，包括：
- 基础四则运算（加减乘除）
- 幂函数运算
- 指数和对数运算
- 三角函数运算
- 统计运算
"""

from mcp.server.fastmcp import FastMCP
import math
import statistics
from typing import List, Union

# 创建MCP服务实例
mcp = FastMCP("Math Calculator Server")

# ============================================================================
# 基础四则运算工具
# ============================================================================

@mcp.tool()
def add(a: float, b: float) -> str:
    """加法运算
    
    Args:
        a: 第一个数字
        b: 第二个数字
        
    Returns:
        计算结果
    """
    result = a + b
    return f"{a} + {b} = {result}"

@mcp.tool()
def subtract(a: float, b: float) -> str:
    """减法运算
    
    Args:
        a: 被减数
        b: 减数
        
    Returns:
        计算结果
    """
    result = a - b
    return f"{a} - {b} = {result}"

@mcp.tool()
def multiply(a: float, b: float) -> str:
    """乘法运算
    
    Args:
        a: 第一个数字
        b: 第二个数字
        
    Returns:
        计算结果
    """
    result = a * b
    return f"{a} × {b} = {result}"

@mcp.tool()
def divide(a: float, b: float) -> str:
    """除法运算
    
    Args:
        a: 被除数
        b: 除数
        
    Returns:
        计算结果或错误信息
    """
    if b == 0:
        return "错误：除数不能为零"
    result = a / b
    return f"{a} ÷ {b} = {result}"

# ============================================================================
# 幂函数和指数运算工具
# ============================================================================

@mcp.tool()
def power(base: float, exponent: float) -> str:
    """幂函数运算
    
    Args:
        base: 底数
        exponent: 指数
        
    Returns:
        计算结果
    """
    try:
        result = base ** exponent
        return f"{base}^{exponent} = {result}"
    except Exception as e:
        return f"计算错误：{str(e)}"

@mcp.tool()
def square_root(number: float) -> str:
    """平方根运算
    
    Args:
        number: 要计算平方根的数字
        
    Returns:
        计算结果或错误信息
    """
    if number < 0:
        return "错误：负数没有实数平方根"
    result = math.sqrt(number)
    return f"√{number} = {result}"

@mcp.tool()
def exponential(x: float) -> str:
    """指数函数运算 (e^x)
    
    Args:
        x: 指数
        
    Returns:
        计算结果
    """
    result = math.exp(x)
    return f"e^{x} = {result}"

@mcp.tool()
def natural_log(x: float) -> str:
    """自然对数运算 (ln(x))
    
    Args:
        x: 要计算对数的数字
        
    Returns:
        计算结果或错误信息
    """
    if x <= 0:
        return "错误：对数的真数必须大于0"
    result = math.log(x)
    return f"ln({x}) = {result}"

@mcp.tool()
def log_base_10(x: float) -> str:
    """常用对数运算 (log10(x))
    
    Args:
        x: 要计算对数的数字
        
    Returns:
        计算结果或错误信息
    """
    if x <= 0:
        return "错误：对数的真数必须大于0"
    result = math.log10(x)
    return f"log10({x}) = {result}"

# ============================================================================
# 三角函数运算工具
# ============================================================================

@mcp.tool()
def sin(angle: float, unit: str = "radians") -> str:
    """正弦函数运算
    
    Args:
        angle: 角度值
        unit: 角度单位 ("radians" 或 "degrees")
        
    Returns:
        计算结果
    """
    if unit == "degrees":
        angle = math.radians(angle)
    result = math.sin(angle)
    return f"sin({angle if unit == 'radians' else math.degrees(angle)}°) = {result}"

@mcp.tool()
def cos(angle: float, unit: str = "radians") -> str:
    """余弦函数运算
    
    Args:
        angle: 角度值
        unit: 角度单位 ("radians" 或 "degrees")
        
    Returns:
        计算结果
    """
    if unit == "degrees":
        angle = math.radians(angle)
    result = math.cos(angle)
    return f"cos({angle if unit == 'radians' else math.degrees(angle)}°) = {result}"

@mcp.tool()
def tan(angle: float, unit: str = "radians") -> str:
    """正切函数运算
    
    Args:
        angle: 角度值
        unit: 角度单位 ("radians" 或 "degrees")
        
    Returns:
        计算结果
    """
    if unit == "degrees":
        angle = math.radians(angle)
    result = math.tan(angle)
    return f"tan({angle if unit == 'radians' else math.degrees(angle)}°) = {result}"

# ============================================================================
# 复合运算工具
# ============================================================================

@mcp.tool()
def calculate_expression(expression: str) -> str:
    """计算数学表达式
    
    Args:
        expression: 数学表达式字符串（支持 +, -, *, /, **, (), sqrt, sin, cos, tan, log, exp）
        
    Returns:
        计算结果或错误信息
    """
    try:
        # 安全的数学函数字典
        safe_dict = {
            "__builtins__": {},
            "sqrt": math.sqrt,
            "sin": math.sin,
            "cos": math.cos,
            "tan": math.tan,
            "log": math.log,
            "log10": math.log10,
            "exp": math.exp,
            "pi": math.pi,
            "e": math.e,
            "abs": abs,
            "pow": pow
        }
        
        result = eval(expression, safe_dict)
        return f"{expression} = {result}"
    except ZeroDivisionError:
        return "错误：除零错误"
    except ValueError as e:
        return f"数值错误：{str(e)}"
    except SyntaxError:
        return "语法错误：表达式格式不正确"
    except Exception as e:
        return f"计算失败：{str(e)}"

@mcp.tool()
def factorial(n: int) -> str:
    """阶乘运算
    
    Args:
        n: 要计算阶乘的非负整数
        
    Returns:
        计算结果或错误信息
    """
    if n < 0:
        return "错误：阶乘只能计算非负整数"
    if n > 170:  # 防止结果过大
        return "错误：数字过大，无法计算阶乘"
    
    result = math.factorial(n)
    return f"{n}! = {result}"

# ============================================================================
# 统计运算工具
# ============================================================================

@mcp.tool()
def calculate_mean(numbers: List[float]) -> str:
    """计算平均值
    
    Args:
        numbers: 数字列表
        
    Returns:
        平均值
    """
    if not numbers:
        return "错误：数字列表不能为空"
    
    result = statistics.mean(numbers)
    return f"平均值：{result}"

@mcp.tool()
def calculate_median(numbers: List[float]) -> str:
    """计算中位数
    
    Args:
        numbers: 数字列表
        
    Returns:
        中位数
    """
    if not numbers:
        return "错误：数字列表不能为空"
    
    result = statistics.median(numbers)
    return f"中位数：{result}"

@mcp.tool()
def calculate_mode(numbers: List[float]) -> str:
    """计算众数
    
    Args:
        numbers: 数字列表
        
    Returns:
        众数或错误信息
    """
    if not numbers:
        return "错误：数字列表不能为空"
    
    try:
        result = statistics.mode(numbers)
        return f"众数：{result}"
    except statistics.StatisticsError:
        return "没有唯一的众数"

@mcp.tool()
def calculate_variance(numbers: List[float]) -> str:
    """计算方差
    
    Args:
        numbers: 数字列表
        
    Returns:
        方差或错误信息
    """
    if len(numbers) < 2:
        return "错误：计算方差至少需要2个数字"
    
    result = statistics.variance(numbers)
    return f"方差：{result}"

@mcp.tool()
def calculate_stdev(numbers: List[float]) -> str:
    """计算标准差
    
    Args:
        numbers: 数字列表
        
    Returns:
        标准差或错误信息
    """
    if len(numbers) < 2:
        return "错误：计算标准差至少需要2个数字"
    
    result = statistics.stdev(numbers)
    return f"标准差：{result}"

# ============================================================================
# 资源定义
# ============================================================================

@mcp.resource("math://constants")
def get_math_constants() -> str:
    """获取数学常数"""
    constants = {
        "π (pi)": math.pi,
        "e (自然常数)": math.e,
        "τ (tau)": math.tau,
        "∞ (infinity)": math.inf
    }
    
    result = "数学常数：\n"
    for name, value in constants.items():
        result += f"  {name}: {value}\n"
    
    return result

@mcp.resource("math://functions")
def get_available_functions() -> str:
    """获取可用的数学函数列表"""
    functions = [
        "基础运算：add, subtract, multiply, divide",
        "幂函数：power, square_root",
        "指数对数：exponential, natural_log, log_base_10",
        "三角函数：sin, cos, tan",
        "复合运算：calculate_expression, factorial",
        "统计函数：calculate_mean, calculate_median, calculate_mode, calculate_variance, calculate_stdev"
    ]
    
    result = "可用的数学函数：\n"
    for func in functions:
        result += f"  • {func}\n"
    
    return result

if __name__ == "__main__":
    mcp.run(transport="stdio")